package base.reflection_demo.demo_03;


import lombok.extern.slf4j.Slf4j;

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.*;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * jdk6以后提供了动态编译机制
 * 应用场景：
 * 1.可以做一个浏览器端编写Java代码，上传服务器编译和运行的在线评测系统
 * 2.服务器动态加载某些类文件进行编译
 *
 * 动态编译的两种做法：
 * 1.通过Runtime调用javac，启动新进程操作(这种并非真正意义上的动态编译，而是效果类似动态编译)
 * Runtime run = Runtime.getRuntime()；
 * Process process = run.exec("javac -cp d:/myjava/ Hello.java");
 *
 * 2.通过JavaCompiler动态编译
 * public static int compileFile(String sourceFile){
 *     // 动态编译
 *     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
*      int result = compiler.run(null, null, null, sourceFile);
 *     log.info("编译成功？{}", result==0?"成功":"失败");
 *     return result;
 * }
 */
@Slf4j
public class DynamicCompiler {

    public static void main(String[] args) throws Exception {
        String sourceFile = "d:/myjava/HelloWorld.java";
        // 编译
        compileFile(sourceFile);

        // 运行
        run();
//        run2();

        // 对流的理解
        stream();
    }


    // 编译程序
    public static int compileFile(String sourceFile){
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        int result = compiler.run(null, null, null, sourceFile);
        log.info("编译成功？{}", result==0?"成功":"失败");
        return result;
    }

    // 运行程序方式一
    public static void run() throws IOException {
        Runtime runtime = Runtime.getRuntime();
        Process process = runtime.exec("java -cp d:/myjava HelloWorld");
        InputStream inputStream = process.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream,"GBK"));
        String line = "";
        while ((line = reader.readLine()) != null){
            log.info("{}",line);
        }
    }
    // 运行程序方式二
    public static void run2() throws Exception {
        URL[] urls = {new URL("file:/d:/myjava/")};
        URLClassLoader loader = new URLClassLoader(urls);
        Class<?> clazz = loader.loadClass("HelloWorld");
        Method method = clazz.getMethod("main", String[].class);
        method.invoke(null, (Object) new String[]{"aa","bb"});//main是static方法，不属于对象，因此第一个入参是null
    }

    /**
     * 节点流和包装流有点类似这种图形结构
     */
    public static void stream () {
        log.info("   内部是节点流    ");
        log.info("|             |");
        log.info(" |           |");
        log.info("  |         |");
        log.info("   |       |");
        log.info("    |     |");
        log.info("     | | |");
        log.info("    |      |");
        log.info("     |    |");
        log.info("      |  |");
        log.info("       ||");
        log.info("    外部是包装流   ");
    }

}
